﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Xml;
using System.Text;
using System.Windows.Forms;
using System.IO;
using rlTodayMakeSkin.Project.XmlElement;
using rlTodayMakeSkin.Project;

namespace rlTodayMakeSkin.GUI
{
    public partial class frmMain : Form, IDisplayProject
    {
        /*FIELDS*/
        private string selectedTool = "";
        //private rlTodayTreeView todayTreeView = null;
        private ToolStripButton lastClickedItem = null;
        private PropertiesWindow propWin;
        private ProjectsManager manProjects;
        private SkinDisplay skinDisplay;
        public static readonly string TITLE = "rlToday Skin Builder - beta version 0.1 ";

        public frmMain()
        {
            InitializeComponent();
            skinDisplay = new SkinDisplay(pnlSkin);
            manProjects = new ProjectsManager(this);
            lastClickedItem = (ToolStripButton)tsSkinElements.Items[0];
            propWin = new PropertiesWindow(this.lstProperties, this.lblPropDescr);
            SelectedControlsManager.initManager(propWin);
            lstProperties.Columns[0].Width = lstProperties.Width / 2;
            lstProperties.Columns[1].Width = lstProperties.Width / 2;
            activeControlProject(false);
        }


        /**********************
         EVENTS
         *********************/
        
        private void mnuOpenSkin_Click(object sender, EventArgs e)
        {
            //Open project Menu
            fbdSkin.RootFolder = Environment.SpecialFolder.MyDocuments;
            fbdSkin.ShowDialog();
            if (fbdSkin.SelectedPath != "")
            {
                string path = fbdSkin.SelectedPath;
                string name = path.Substring(path.LastIndexOf('\\') + 1);
                //controls that exists skin.xml file
                if (File.Exists(path + "\\skin.xml") == false)
                    MessageBox.Show("Invalid folder selected. The folder must be contain a valid skin.xml file",
                        TITLE);
                else
                {
                    rlTodayProject prj = null;
                    try
                    {
                        prj = manProjects.loadProject(fbdSkin.SelectedPath);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Error while loading skin:\n\t" + ex.Message, TITLE);
                        return;
                    }
                    //todayTreeView = new rlTodayTreeView(treeSkin, prj);
                    activeControlProject(true);
                    SelectedControlsManager.changeSelectedProject(prj.getSkinDisplay());
                    manProjects.activeProject(prj.Name);
                }
            }
        }

        //Save project Menu
        private void mnuSaveSkin_Click(object sender, EventArgs e)
        {
            if (manProjects.getCurrentProject() == null) return;
            try
            {
                manProjects.getCurrentProject().save();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error while saving:\n\t" + ex.Message, TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        //exit Menu
        private void mnuExit_Click(object sender, EventArgs e)
        {
            if (askToSave())
            { //controls if current project is saved
                manProjects.closeCurrentProject();
                Application.Exit();
            }
        }

        //toolbar element clicked
        private void tsSkinElements_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            lastClickedItem.Checked = false;
            //if Pointer tool is clicked then unselects controls
            if (e.ClickedItem.Text == tsSkinElements.Items[0].Text)
            {
                //SelectedControlsManager.GetManager().removeAll();
                pnlSkin.Cursor = Cursors.Arrow;
            }
            else
            {
                pnlSkin.Cursor = Cursors.Hand;
            }
            selectedTool = e.ClickedItem.Text;
            lastClickedItem = (ToolStripButton)e.ClickedItem;
        }

        //click on project surface
        private void pnlSkin_MouseClick(object sender, MouseEventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            rlTodayXmlElement el = manProjects.getCurrentProject().getNewElement(selectedTool);
            
            SelectedControlsManager.GetManager().removeAll();
            propWin.unselect();
            if (el != null)
            {
                el.X = e.X;
                el.Y = e.Y;
                manProjects.getCurrentProject().addElement(el, true);
            }
            selectedTool = "";
            tsSkinElements.Items[0].PerformClick();//actives the pointer tool
            this.Cursor = Cursors.Arrow;
        }


        /*********************
        IMPLEMENTED METHODS FOR IDisplayProject INTERFACE
         *********************/
        public void showProject(rlTodayProject prj)
        {
            activeControlProject(true);
            SelectedControlsManager.GetManager().removeAll();
            propWin.setCurrentProject(prj);
            SelectedControlsManager.changeSelectedProject(skinDisplay);
            //add project elements to skin display
            foreach (rlTodayXmlElement el in prj.Elements)
            {
                pnlSkin.Controls.Add(el.GetGuiControl());
            }
            //pnlSkin.Refresh();
            skinDisplay.drawAll();
            this.Text = TITLE + " - " + prj.Name;
        }


        public ISkinDisplay getSkinDisplay()
        {
            return skinDisplay;
        }

        public void closingProject(rlTodayProject p)
        {
            skinDisplay.Clear();
            //in this version cab be there only a project at times: disabled related controls
            activeControlProject(false);
        }

        /*********************
        PRIVATE METHODS
         *********************/
        private void mnuNewSkin_Click(object sender, EventArgs e)
        {
            //Create new skin. For now is not allowed to have multiple project. Future impelmentation
            rlTodayProject p = manProjects.getCurrentProject();
            if (p != null)
            {
                //ask if really close current project
                if (p.IsModified == false) p.save();
                manProjects.closeProject(p.Name);
            }
            //show folder browse dialog
            fbdSkin.RootFolder = Environment.SpecialFolder.MyDocuments;
            fbdSkin.ShowDialog();
            if (fbdSkin.SelectedPath != "")
            {
                p = manProjects.addProject(fbdSkin.SelectedPath);
                this.Text = TITLE + " - " + p.Name;
            }
            else
                return;
            manProjects.activeProject(p.Name);
        }



        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (askToSave() == false)
                e.Cancel = true;
        }

        private void mnuCloseProject_Click(object sender, EventArgs e)
        {
            //Close current project
            if (askToSave() == false) return;
            propWin.unselect();
            manProjects.closeProject(manProjects.getCurrentProject().Name);
            skinDisplay.Clear();
        }

        private void mnuRemoveElement_Click(object sender, EventArgs e)
        {
            //Delete all select controls;
            SkinControl[] scs = SelectedControlsManager.GetManager().getSelectedControls();
            if (scs.Length == 0) return;
            foreach (SkinControl c in scs)
            {
                manProjects.getCurrentProject().deleteElement(c.GetTodayElement());
                pnlSkin.Controls.Remove(c);
            }
            //clears property list
            propWin.unselect();
        }

        private void pnlSkin_Resize(object sender, EventArgs e)
        {
            //Resizing the project surface
            int minH = gbProperties.MinimumSize.Height;
            this.Width = pnlSkin.Left + pnlSkin.Width + gbProperties.Width + 10;
            gbProperties.Left = pnlSkin.Left + pnlSkin.Width + 5;
            if (pnlSkin.Height > minH)
            {
                //strech toolbar and properties window
                this.Height = pnlSkin.Height + 5;
                gbProperties.Height = pnlSkin.Height + gbProperties.Top;
                tsSkinElements.Height = pnlSkin.Height + tsSkinElements.Top;
            }
            else {
                gbProperties.Height = minH;
                this.Height = gbProperties.Height + gbProperties.Top + 35;
                tsSkinElements.Height = minH;
                //pnlSkin.Top = (this.Height - pnlSkin.Height) / 2;
            }

        }


        private void gbProperties_Resize(object sender, EventArgs e)
        {
            //Resizing properties window
            lblPropDescr.Top = gbProperties.Height - lblPropDescr.Height - 5;
            lstProperties.Height = lblPropDescr.Top - lstProperties.Top - 2;
        }

        private void activeControlProject(bool active)
        {
            //enable or disable controls that "control" the project
            Control[] ctrls = {tsSkinElements, pnlSkin, gbProperties};
            foreach (Control c in ctrls)
                c.Enabled = active;
            //same thing with menus
            ToolStripItem[] menus = {mnuProject, mnuElement, mnuSave, mnuSaveAs, tsbDelElement, tsbPrjProp, tsbSave, tsbSendToBack };
            foreach (ToolStripItem m in menus)
                m.Enabled = active;
        }



        private void mnuShowProperty_Click(object sender, EventArgs e)
        {
            //Show project property window. Everything is done by it
            ProjectPropertiesWindow ppw = new ProjectPropertiesWindow(manProjects.getCurrentProject());
        }

        //Controls if current project is not saved and ask if save it or cancel operatation
        //return true project is saved (or not nedded), false otherwise
        private bool askToSave()
        {
            rlTodayProject prj = manProjects.getCurrentProject();
            if (prj != null && prj.IsModified == true)
            {
                //ask if save changes
                DialogResult res = MessageBox.Show("Current project is been modified. Do you want to save changes?",
                    TITLE, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (res == DialogResult.Yes)
                    prj.save();
                else if (res == DialogResult.Cancel)
                    return false; //not exit
            }
            return true;
        }


        private void mnuSendToBack_Click(object sender, EventArgs e)
        {//Send the selected skin elment back to overlapped elments
            SelectedControlsManager.GetManager().SendToBack();
        }

        private void mnuSaveAs_Click(object sender, EventArgs e)
        {//Save project in an other path
            fbdSkin.ShowDialog();
            if (fbdSkin.SelectedPath != "")
            {
                try
                {
                    string newPath = fbdSkin.SelectedPath + "\\skin.xml";
                    if (File.Exists(newPath))
                    {
                        DialogResult res = 
                            MessageBox.Show("Already exists a skin in this folder. Overwrite it?", TITLE, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                        if (res == DialogResult.No) return;
                    }
                    File.Copy(manProjects.getCurrentProject().Path + "\\skin.xml", newPath, true);
                    manProjects.getCurrentProject().Path = fbdSkin.SelectedPath;
                    Text = TITLE + " - " + manProjects.getCurrentProject().Name;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error while saving:\n\t" + ex.Message, TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void closeProjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            manProjects.closeCurrentProject();
        }


        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Application written by Daniele Cangemi (cdaniele@hotmail.it)\n" +
            "Binaries and source code are distribuited under GPL-2 license (see gpl-2_0.txt)\n"+
            "and can be found here: http://code.google.com/p/rltodayskinmaker/.",
            TITLE, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }  
        /********************
         PRIVATE CLASS that implements ISkinDisplay interface
         *******************/

        private class SkinDisplay : ISkinDisplay{

            private List<SkinControl> skinControls = new List<SkinControl>();
            private Control surface;

            public SkinDisplay(Control theSkinDisplay){
                surface = theSkinDisplay;
            }

            /// <summary>
            /// Adds a new element to project and shows it in the skin display
            /// </summary>
            /// <param name="el">element to add</param>
            /// <param name="selectIt">true if need to select new control</param>
            public void addSkinElement(rlTodayXmlElement el, bool selectIt)
            {
                SkinControl sc = new SkinControl(el);
                surface.Controls.Add(sc);
                skinControls.Add(sc);
                sc.DrawControl();
                if (selectIt) SelectedControlsManager.GetManager().add(sc);
                
            }

            /// <summary>
            /// Retrives elements in this skin
            /// </summary>
            /// <returns>an array of SkinControl</returns>
            public SkinControl[] getSkinElement()
            {
                return skinControls.ToArray();
            }

            /// <summary>
            /// Readraws all control in the display
            /// </summary>
            public void drawAll()
            {
                foreach (SkinControl sc in skinControls)
                {
                    sc.DrawControl();
                }
            }

            /// <summary>
            /// clears display and remove all elements
            /// </summary>
            public void Clear()
            {
                SelectedControlsManager.GetManager().removeAll();
                surface.Controls.Clear();
            }

            /// <summary>
            /// Sets, ges height of the surface project
            /// </summary>
            public int Height
            {
                get { return surface.Height; }
                set { surface.Height = value; }
            }

            /// <summary>
            /// Sets, gests width of the surface project
            /// </summary>
            public int Width
            {
                get { return surface.Width; }
                set { surface.Width = value; }
            }

        }


        //end inner class SkinDisplay

      
    }//end class rlTodayMakeSkin

}//end namespace
